home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 6 / The Arsenal Files 6 (Arsenal Computer).ISO / os2 / am4pmsrc.zip / AM4PMW.C < prev    next >
Text File  |  1996-01-01  |  58KB  |  2,582 lines

  1. // Thomas Answering machine for PM
  2.  
  3. // File:          AM4PMW.c
  4. // Description:   Send data to modem
  5.  
  6. // History
  7. // 930206 TO      Now it exists...
  8. // 930430 TO      Change sub command interface to subroutines
  9. // 940226 TO      Adaptions to Rockwell modems
  10.  
  11. #define INCL_BASE
  12. #define INCL_WINSHELLDATA
  13. #include <os2.h>
  14.  
  15. #define INCL_REXXSAA
  16. #include <rexxsaa.h>                   /* needed for RexxStart()     */
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <stdarg.h>
  22. #include <process.h>
  23. #include <stddef.h>
  24. #include <malloc.h>
  25. #include <ctype.h>
  26. #include <io.h>
  27. #include <conio.h>
  28. #include <errno.h>
  29.  
  30. #include "am4pm.h"
  31.  
  32. #define RQMAX           100      // Maximum number of records in event queue
  33. #define RQLOW           90       // Records in queue when ok to continue
  34.  
  35. typedef struct _QUEUERECORD
  36. {
  37.    PVOID pData;
  38.    ULONG ulLen, ulMsg;
  39.    struct _QUEUERECORD * pNext;
  40. } QUEUERECORD;
  41.  
  42. typedef QUEUERECORD * PQUEUERECORD;
  43.  
  44. // Controll of the receiving thread
  45. HEV semStopRead;
  46. HEV semStopedReading;
  47. HEV semGoOnRead;
  48. HEV semWordInBuff;
  49.  
  50.  
  51. HMTX semCom;   // Requested when the COM port is open
  52.  
  53. // Variables for the internal que
  54. static PQUEUERECORD pFirstQR=NULL;
  55. static PQUEUERECORD pLastQR=NULL;
  56. static USHORT usQueueLen=0;
  57. static HEV semQueueEmpty;
  58. static HEV semQueueFull;
  59. static CHAR szSemCom[]="\\SEM32\\AM4PM\\COM";
  60.  
  61. static CHAR szExitName[]="AM4PMExit";
  62.  
  63. HFILE hRec;
  64. HFILE hCom=0l;
  65. volatile USHORT usGlobalState=GS_START;
  66. volatile ULONG ulRecTime;
  67. volatile BOOL bDLEConv;
  68. static int thidRec;     // Thread id for the receiving thread
  69.  
  70. volatile CHAR * pchSendBuff;
  71. volatile ULONG ulSendBuffLen;
  72. volatile CHAR szActiveDLECodes[DLECODES] = {'0'};
  73.  
  74. static const CHAR achZyXKey[]={'Z','y','X','E','L',2};
  75. static const CHAR achAM4PMKey[]={'A','M','4','P','M',2};
  76. static CHAR szCrntMFile[15];
  77.  
  78. static SHORT CallRexx
  79. (
  80.    PCHAR pszFile,
  81.    ...
  82. )
  83. {
  84.  
  85.    RXSTRING arg[5];                   /* argument string for REXX  */
  86.    RXSTRING rexxretval;               /* return value from REXX    */
  87.    APIRET   rc;                        /* return code from REXX     */
  88.    SHORT    sRexxRc = 0;               /* return code from function */
  89.    va_list  arg_marker;
  90.    ULONG    ulNr;                      /* Number of parameters */
  91.    static RXSYSEXIT MyRxExit[]=
  92.    {
  93.       {szExitName, RXINI},
  94.       {szExitName, RXTER},
  95.       {szExitName, RXSIO},
  96.       {NULL, RXENDLST}
  97.    };
  98.  
  99.    rexxretval.strlength = 0L;          /* initialize return to empty*/
  100.  
  101.    va_start(arg_marker, pszFile);
  102.  
  103.    for (ulNr=0; ulNr< sizeof arg / sizeof arg[0]; ulNr++)
  104.    {
  105.       arg[ulNr].strptr=va_arg(arg_marker, PCHAR);
  106.       if (arg[ulNr].strptr == NULL)
  107.          break;
  108.       arg[ulNr].strlength=strlen(arg[ulNr].strptr);
  109.    }
  110.  
  111.    if (fDebug)
  112.       dprintf("Calling REXX '%s(%u)'\n", pszFile, ulNr);
  113.       
  114.    rc=RexxStart(ulNr, arg, pszFile, 0, "CMD", RXSUBROUTINE, MyRxExit, &sRexxRc, &rexxretval);
  115.    DosFreeMem(rexxretval.strptr);          /* Release storage       */
  116.    if (rc)
  117.    {
  118.       if (fDebug)
  119.          dprintf("Error %ul calling REXX\n", rc);
  120.       LogNumMessage(6, rc, pszFile, NULL);
  121.       return 1;
  122.    }
  123.  
  124.    if (fDebug)
  125.       dprintf("REXX function returned %i\n", sRexxRc);
  126.    return sRexxRc;
  127. }
  128.  
  129.  
  130. static ULONG WaitQueue
  131. (
  132.    ULONG ulMsgMask,
  133.    PPVOID ppData,
  134.    PULONG pulLen,
  135.    ULONG ulTO
  136. )
  137. {
  138.    PQUEUERECORD pQR, pPrevQR;
  139.    ULONG ulCount, ulMsg;
  140.    USHORT res;
  141.  
  142.    for (;;)
  143.    {
  144.       if (usQueueLen)
  145.       {
  146.          DosEnterCritSec();
  147.          for (pQR=pFirstQR, pPrevQR=NULL; pQR != NULL; pPrevQR=pQR, pQR=pQR->pNext)
  148.          {
  149.             if (pQR->ulMsg & ulMsgMask)
  150.             {
  151.                if (pPrevQR==NULL)
  152.                   pFirstQR=pQR->pNext;
  153.                else
  154.                   pPrevQR->pNext=pQR->pNext;
  155.                if (pQR->pNext==NULL)
  156.                   pLastQR=pPrevQR;
  157.                   
  158.                usQueueLen--;
  159.                   
  160.                DosExitCritSec();
  161.                if (usQueueLen==RQLOW)
  162.                   DosPostEventSem(semQueueFull);
  163.                *pulLen=pQR->ulLen;
  164.                *ppData=pQR->pData;
  165.                ulMsg=pQR->ulMsg;
  166.                free(pQR);
  167.  
  168.                return ulMsg;
  169.             }
  170.          }
  171.          DosExitCritSec();
  172.       }
  173.  
  174.       if (ulTO==SEM_IMMEDIATE_RETURN)
  175.          return 0;
  176.       res=DosWaitEventSem(semQueueEmpty, ulTO);
  177.       if (res)
  178.          return 0l;
  179.       DosResetEventSem(semQueueEmpty, &ulCount);
  180.    }
  181.    return 0l;
  182. }
  183.  
  184.  
  185. static void ClearQueue
  186. (
  187.    ULONG ulMsgMask,
  188.    ULONG ulTO
  189. )
  190. {
  191.    ULONG ulMsg, ulLen;
  192.    PVOID pData;
  193.  
  194.    for (;;)
  195.    {
  196.       ulMsg = WaitQueue(ulMsgMask, &pData, &ulLen, ulTO);
  197.       if (ulMsg == 0l)
  198.          break;
  199.       free(pData);
  200.    }
  201. }
  202.  
  203.  
  204. void QueueData
  205. (
  206.    ULONG ulMsg,
  207.    PVOID pData,
  208.    ULONG ulLen
  209. )
  210. {
  211.    PQUEUERECORD pQR;
  212.    ULONG ulCount;
  213.  
  214.    pQR=malloc(sizeof(QUEUERECORD));
  215.    if (pQR==NULL)
  216.    {
  217.       LogMessage(1, NULL); // Error allocation memory
  218.       return;
  219.    }
  220.    pQR->ulMsg=ulMsg;
  221.    pQR->ulLen=ulLen;
  222.    pQR->pData=malloc(ulLen | 1l);
  223.    if (pQR->pData==NULL)
  224.    {
  225.       LogMessage(1, NULL); // Error allocating memory
  226.       return;
  227.    }
  228.    pQR->pNext=NULL;
  229.    if (ulLen)
  230.       memcpy(pQR->pData, pData, ulLen);
  231.  
  232.    DosEnterCritSec();
  233.    if (usQueueLen==RQMAX)
  234.    {
  235.       DosExitCritSec();
  236.       DosWaitEventSem(semQueueFull, SEM_INDEFINITE_WAIT);
  237.       DosResetEventSem(semQueueFull, &ulCount);
  238.       DosEnterCritSec();
  239.    }
  240.  
  241.    if (usQueueLen)
  242.       pLastQR->pNext=pQR;
  243.    else
  244.       pFirstQR=pQR;
  245.  
  246.    pLastQR=pQR;
  247.    usQueueLen++;
  248.    DosExitCritSec();
  249.  
  250.    DosPostEventSem(semQueueEmpty);
  251. }
  252.  
  253.  
  254. USHORT SendIt(void * str, USHORT antal)
  255. {
  256.    ULONG n;
  257.    APIRET res;
  258.  
  259.    res=DosWrite(hCom, str, antal, &n);
  260.    if (res)
  261.    {
  262.       LogDosMessage(res, 5, NULL);  // Error sending
  263.       return 1;
  264.    }
  265.    return 0;
  266. }
  267.  
  268.  
  269. static USHORT SendHayes    // Sending to the port and waits for an answer.
  270. (
  271.    PCHAR szStr
  272. )
  273. {
  274.    USHORT i, res;
  275.  
  276.    for (i=0; szStr[i]; i++)
  277.    {
  278.       res=SendIt(szStr+i, 1);
  279.       if (res)
  280.          return res;
  281.    }
  282.    return 0;
  283. }
  284.  
  285.  
  286. static USHORT SendHayesResp // Sending to the port and waits for an answer.
  287. (
  288.    PCHAR szStr,
  289.    PCHAR szResp,
  290.    ULONG ulTO
  291. )
  292. {
  293.    USHORT res;
  294.    ULONG ulLen, ulMsg;
  295.    PVOID pData;
  296.  
  297.    ClearQueue(IM_STRFROMDCE, SEM_IMMEDIATE_RETURN);
  298.  
  299.    if (fDebug)
  300.       dprintf("Sending: %s\nWaiting for '%s'.\n", szStr, szResp);
  301.  
  302.    res=SendIt(szStr, strlen(szStr));
  303.    if (res)
  304.       return res;
  305.  
  306.    for (;;)
  307.    {
  308.       ulMsg=WaitQueue(IM_STRFROMDCE, &pData, &ulLen, ulTO);
  309.       if (ulMsg != IM_STRFROMDCE)
  310.       {
  311.          if (fDebug)
  312.             dprintf("Timeout waiting for '%s'\n", szResp);
  313.          LogMessage(20, szResp, szStr, NULL); // Timeout waiting for AT command
  314.          return 2;
  315.       }
  316.  
  317.       if (strcmp(pData, szResp) == 0)
  318.          break;
  319.  
  320.       if (fDebug)
  321.          dprintf("Waiting for '%s' but got '%s'\n", szResp, pData);
  322.  
  323.       free(pData);
  324.    }
  325.  
  326.    free(pData);
  327.    return 0;
  328. }
  329.  
  330.  
  331. static USHORT SendHayes2 // Sending to the port and waits for an answer.
  332. (
  333.    PCHAR szStr,   // String with command{response}..
  334.    ULONG ulTO,
  335.    USHORT usRetries
  336. )
  337. {
  338.    USHORT i, res, pos;
  339.    CHAR szCmd[MAXHAYESMSG+1], szResp[MAXHAYESMSG];
  340.  
  341.    for (pos=0; szStr[pos] != '\0'; pos++)
  342.    {
  343.       for (i=0; szStr[pos] != '\0' && szStr[pos] != '{' && i < sizeof szCmd; i++, pos++)
  344.          szCmd[i] = szStr[pos];
  345.  
  346.       if (i >= sizeof szCmd || szStr[pos] != '{')
  347.       {
  348.          if (fDebug)
  349.             dprintf("Invalid response string in '%s'\n", szStr);
  350.          return 3;
  351.       }
  352.  
  353.       szCmd[i] = '\r';
  354.       szCmd[i+1] = '\0';
  355.  
  356.       pos++;
  357.       for (i=0; szStr[pos] != '\0' && szStr[pos] != '}' && i < sizeof szResp; i++, pos++)
  358.          szResp[i] = szStr[pos];
  359.  
  360.       if (i >= sizeof szResp || szStr[pos] != '}')
  361.       {
  362.          if (fDebug)
  363.             dprintf("Invalid response string in '%s'\n", szStr);
  364.          return 3;
  365.       }
  366.  
  367.       szResp[i] = '\0';
  368.  
  369.       for (i=0; i<usRetries; i++)
  370.       {
  371.          res = SendHayesResp(szCmd, szResp, ulTO);
  372.          if (res == 0)
  373.             break;
  374.       }
  375.  
  376.       if (res)
  377.          return res;
  378.    }
  379.  
  380.    return 0;
  381. }
  382.  
  383.  
  384. static void SetComTOZero(void)
  385. {
  386.    DCBTYPE DCB;
  387.    USHORT res;
  388.    char szStr[10];
  389.    ULONG ulDLen, ulPLen;
  390.  
  391.    ulPLen=0;
  392.    ulDLen=sizeof DCB;
  393.    res=DosDevIOCtl(hCom, 1, 0x73, NULL, 0, &ulPLen, &DCB, ulDLen, &ulDLen);
  394.    if (res)
  395.    {
  396.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "read mode", NULL); //Fel vid IOCtl
  397.       return;
  398.    }
  399.  
  400.    DCB.usWTime=0;
  401.    DCB.usRTime=0;
  402.  
  403.    ulDLen=0;
  404.    ulPLen=sizeof DCB;
  405.    res=DosDevIOCtl(hCom, 1, 0x53, &DCB, ulPLen, &ulPLen, NULL, ulDLen, &ulDLen);
  406.    if (res)
  407.    {
  408.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "set mode", NULL); //Fel vid IOCtl
  409.       return;
  410.    }
  411. };
  412.  
  413.  
  414. static void SaveRestComMode(BOOL fSave)
  415. {
  416.    static DCBTYPE DCB;
  417.    USHORT res;
  418.    static UCHAR achLineParams[4];
  419.    char szStr[10];
  420.    ULONG ulDLen, ulPLen;
  421.  
  422.    if (fSave)
  423.    {
  424.       if (fDebug)
  425.          dprintf("Saving COM parameters\n");
  426.  
  427.       ulPLen=0;
  428.       ulDLen=sizeof DCB;
  429.       res=DosDevIOCtl(hCom, 1, 0x73, NULL, 0, &ulPLen, &DCB, ulDLen, &ulDLen);
  430.       if (res)
  431.       {
  432.          LogDosMessage(res, 50, _itoa(res, szStr, 10), "read mode", NULL); //Fel vid IOCtl
  433.          exit(1);
  434.       }
  435.  
  436.       ulPLen=0;
  437.       ulDLen=sizeof achLineParams;
  438.       res=DosDevIOCtl(hCom, 1, 0x62, NULL, 0, &ulPLen, &achLineParams, ulDLen, &ulDLen);
  439.       if (res)
  440.       {
  441.          LogDosMessage(res, 50, _itoa(res, szStr, 10), "line char", NULL); //Fel vid IOCtl
  442.          exit(1);
  443.       }
  444.       return;
  445.    }
  446.    
  447.  
  448.    if (fDebug)
  449.       dprintf("Restoring COM parameters\n");
  450.  
  451.    ulDLen=0;
  452.    ulPLen=sizeof DCB;
  453.    res=DosDevIOCtl(hCom, 1, 0x53, &DCB, ulPLen, &ulPLen, NULL, ulDLen, &ulDLen);
  454.    if (res)
  455.    {
  456.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "set mode", NULL); //Fel vid IOCtl
  457.       exit(1);
  458.    }
  459.  
  460.    ulDLen=0;
  461.    ulPLen=sizeof achLineParams-1;   // Not 'Transmitting break'
  462.    res=DosDevIOCtl(hCom, 1, 0x42, achLineParams, ulPLen, &ulPLen, NULL, ulDLen, &ulDLen);
  463.    if (res)
  464.    {
  465.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "line char", NULL); //Fel vid IOCtl
  466.       exit(1);
  467.    }
  468. };
  469.  
  470.  
  471. static USHORT OpenCom(void)
  472. {
  473.    USHORT res;
  474.    ULONG action;
  475.  
  476.    DosRequestMutexSem(semCom, SEM_INDEFINITE_WAIT);
  477.  
  478. // res=DosOpen(ParamBlock.szCom,&hCom,&action,0l,0,FILE_OPEN,OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR, 0l);
  479.    res=DosOpen(ParamBlock.szCom,&hCom,&action,0l,0,FILE_OPEN,OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | OPEN_FLAGS_FAIL_ON_ERROR, 0l);
  480.    if (res)
  481.    {
  482. //    LogDosMessage(res, 14, ParamBlock.szCom, NULL); // Error opening file
  483.       DosReleaseMutexSem(semCom);
  484.       return res;
  485.    }
  486.  
  487.    return 0;
  488. }
  489.  
  490.  
  491. static void SetComMode(void)
  492. {
  493.    DCBTYPE DCB;
  494.    USHORT res;
  495.    static UCHAR achLineParams[3]={8,0,0}; // 8,N,1
  496.    char szStr[10];
  497.    ULONG ulDLen, ulPLen;
  498.  
  499.    ulPLen=0;
  500.    ulDLen=sizeof DCB;
  501.    res=DosDevIOCtl(hCom, 1, 0x73, NULL, 0, &ulPLen, &DCB, ulDLen, &ulDLen);
  502.    if (res)
  503.    {
  504.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "read mode", NULL); //Fel vid IOCtl
  505.       exit(1);
  506.    }
  507.  
  508.    DCB.usWTime=SENDTO*100;
  509.    DCB.usRTime=READTO*100;
  510.  
  511.    DCB.chFlag1 &= 0x84;
  512.    DCB.chFlag1 |= 0x01;
  513.  
  514. // DCB.chFlag2 = 0x85;  // XON
  515.  
  516. // DCB.chFlag3 &= 0xf8;
  517. // DCB.chFlag3 |= 0x04;
  518.  
  519.  
  520.    // New test
  521.    DCB.chFlag2 = 0x80;
  522.    DCB.chFlag3 = 0xD4;
  523.  
  524.    ulDLen=0;
  525.    ulPLen=sizeof DCB;
  526.    res=DosDevIOCtl(hCom, 1, 0x53, &DCB, ulPLen, &ulPLen, NULL, ulDLen, &ulDLen);
  527.    if (res)
  528.    {
  529.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "set mode", NULL); //Fel vid IOCtl
  530.       exit(1);
  531.    }
  532.  
  533.    ulDLen=0;
  534.    ulPLen=sizeof ParamBlock.ulBaud;
  535.    res=DosDevIOCtl(hCom, 1, 0x41, &(ParamBlock.ulBaud), ulPLen, &ulPLen, NULL, ulDLen, &ulDLen);
  536.    if (res)
  537.    {
  538.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "baud", NULL); //Fel vid IOCtl
  539.       exit(1);
  540.    }
  541.  
  542.    ulDLen=0;
  543.    ulPLen=sizeof achLineParams;
  544.    res=DosDevIOCtl(hCom, 1, 0x42, achLineParams, ulPLen, &ulPLen, NULL, ulDLen, &ulDLen);
  545.    if (res)
  546.    {
  547.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "line char", NULL); //Fel vid IOCtl
  548.       exit(1);
  549.    }
  550. };
  551.  
  552.  
  553. static void ShutDown(void)
  554. {
  555.    usGlobalState=GS_ENDING;
  556.    DosPostEventSem(semGoOnRead);
  557. }
  558.  
  559.  
  560. static USHORT HangUp
  561. (
  562.    void
  563. )
  564. {
  565.    return SendHayes2(ParamBlock.szATHangUp, MAXWAITDCE, 3);
  566. }
  567.  
  568.  
  569. static HFILE CreateMFile(void)
  570. {
  571.    USHORT res;
  572.    HFILE hF;
  573.    ULONG ulAction;
  574.  
  575.    for (;;)
  576.    {
  577.       ParamBlock.ulLastFileID++;
  578.       sprintf(szCrntMFile, "M%lu.%s", ParamBlock.ulLastFileID, ParamBlock.szFileExtension);
  579.       if (access(szCrntMFile, 0)==-1)
  580.       {
  581.          if (errno == ENOENT)
  582.             break;
  583.          return 0;
  584.       }
  585.       if (fDebug)
  586.          dprintf("File '%s' already exists\n", szCrntMFile);
  587.  
  588.    }
  589.    if (fDebug)
  590.       dprintf("Creating file '%s'\n", szCrntMFile);
  591.    res=DosOpen(szCrntMFile, &hF, &ulAction, 0l, FILE_NORMAL, OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_WRITEONLY, 0l);
  592.    if (res)
  593.    {
  594.       LogNumMessage(2, res, szCrntMFile, NULL); // Error opening file
  595.       return 0;
  596.    }
  597.  
  598.    return hF;
  599. }
  600.  
  601.  
  602. static void SetComXONXOFF(BOOL fIn, BOOL fOut)
  603. {
  604.    DCBTYPE DCB;
  605.    USHORT res;
  606.    char szStr[10];
  607.    ULONG ulDLen, ulPLen;
  608.  
  609.    ulPLen=0;
  610.    ulDLen=sizeof DCB;
  611.    res=DosDevIOCtl(hCom, 1, 0x73, NULL, 0, &ulPLen, &DCB, ulDLen, &ulDLen);
  612.    if (res)
  613.    {
  614.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "read mode", NULL); //Fel vid IOCtl
  615.       return;
  616.    }
  617.  
  618.    if (fIn)
  619.       DCB.chFlag2 |= 1; // XON/XOFF on transmit
  620.    else
  621.       DCB.chFlag2 &= ~1; // No XON/XOFF on transmit
  622.  
  623.    if (fOut)
  624.       DCB.chFlag2 |= 2; // XON/XOFF on receive
  625.    else
  626.       DCB.chFlag2 &= ~2; // No XON/XOFF on receive
  627.  
  628.    ulDLen=0;
  629.    ulPLen=sizeof DCB;
  630.    res=DosDevIOCtl(hCom, 1, 0x53, &DCB, ulPLen, &ulPLen, NULL, ulDLen, &ulDLen);
  631.    if (res)
  632.    {
  633.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "set mode", NULL); //Fel vid IOCtl
  634.       return;
  635.    }
  636. };
  637.  
  638. #if 0
  639. static void PrintComStatus(void)
  640. {
  641.    BYTE bStatus;
  642.    USHORT res;
  643.    char szStr[10];
  644.    ULONG ulDLen, ulPLen;
  645.  
  646.    ulPLen=0;
  647.    ulDLen=sizeof bStatus;
  648.    res=DosDevIOCtl(hCom, 1, 0x64, NULL, 0, &ulPLen, &bStatus, ulDLen, &ulDLen);
  649.    if (res)
  650.    {
  651.       LogDosMessage(res, 50, _itoa(res, szStr, 10), "get status", NULL); //Fel vid IOCtl
  652.       return;
  653.    }
  654.  
  655.    if (fDebug)
  656.       dprintf("Com status: %x\n", bStatus);
  657. };
  658. #endif
  659.  
  660.  
  661. static void PlayFile
  662. (
  663.    PRXSTRING prxsRet,
  664.    PCHAR pszFile
  665. )
  666. {
  667.    CHAR chRet=' ', szVSMCmd[MAXHAYESMSG];
  668.    ULONG ulMsg, ulLen, ulAction, ulSLen;
  669.    PVOID pData;
  670.    BOOL fFirst, bOtherEvent=FALSE, bDoConvDLE = TRUE;
  671.    HFILE fh;
  672.    ZYXHEAD zh;
  673.    USHORT res, i, usType;
  674.    static CHAR achFileB[SENDBUFFLEN], achOutB[SENDBUFFLEN*2];
  675.  
  676.    prxsRet->strlength=1;
  677.  
  678.    // Make sure the input queue is empty
  679.    ClearQueue(IM_STRFROMDCE | IM_DLEFROMDCE | IM_STOP, SEM_IMMEDIATE_RETURN);
  680.  
  681.    res=DosOpen(pszFile, &fh, &ulAction, 0l, FILE_NORMAL, OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, 0l);
  682.  
  683.    if (res)
  684.    {
  685.       LogNumMessage(2, res, pszFile, NULL); // Error opening file
  686.       prxsRet->strptr[0]='!';
  687.       return;
  688.    }
  689.  
  690.    // Determine if it is a ZyXEL file. Otherwise just send it as it is.
  691.    DosRead(fh, &zh, sizeof zh, &ulLen);
  692.    if (ulLen==sizeof zh && memcmp(achZyXKey, &zh, sizeof achZyXKey)==0)
  693.    {
  694.       if (zh.usType <= 2)
  695.       {
  696.          if (fDebug)
  697.             dprintf("Old ZyXEL file detected.\n");
  698.          usType = zh.usType+1;
  699.       }
  700.       else
  701.       {
  702.          if (fDebug)
  703.             dprintf("New ZyXEL file detected.\n");
  704.          usType = zh.usType-2;
  705.          bDoConvDLE = FALSE;
  706.       }
  707.    }
  708.    else
  709.    {
  710.       if (ulLen==sizeof zh && memcmp(achAM4PMKey, &zh, sizeof achAM4PMKey)==0)
  711.       {
  712.          if (fDebug)
  713.             dprintf("A generic AM4PM file detected\n");
  714.          usType = zh.usType+1;
  715.          bDoConvDLE = FALSE;
  716.       }
  717.       else
  718.       {
  719.          if (fDebug)
  720.             dprintf("An unkown file detected\n");
  721.          DosSetFilePtr(fh, 0l, FILE_BEGIN, &ulLen);
  722.          usType=1;  // CELP
  723.       }
  724.    }
  725.  
  726.    sprintf(szVSMCmd, ParamBlock.szATVoiceMode, usType);
  727.    res=SendHayes2(szVSMCmd, 3000, 3);
  728.    if (res)
  729.    {
  730.       if (fDebug)
  731.          dprintf("Send error %u\n", res);
  732.       DosClose(fh);
  733.       prxsRet->strptr[0]='!';
  734.       return;
  735.    }
  736.  
  737.    SetComXONXOFF(TRUE, FALSE);
  738.  
  739.    for (fFirst=TRUE;;)
  740.    {
  741.       res=DosRead(fh, achFileB, SENDBUFFLEN, &ulLen);
  742.       if (fDebug && res)
  743.          dprintf("Error %u reading\n", res);
  744.       if (ulLen == 0l)
  745.       {
  746.          SendHayes2(ParamBlock.szATVoiceEndTX, 3000l, 3);
  747.          break;
  748.       }
  749.  
  750.       if (bDoConvDLE)
  751.       {
  752.          for (i=0, ulSLen=0; i<ulLen; i++)
  753.          {
  754.             achOutB[ulSLen++]=achFileB[i];
  755.             if (achFileB[i]==16) // DLE
  756.                achOutB[ulSLen++]=achFileB[i];
  757.          }
  758.       }
  759.  
  760.       if (fFirst)
  761.       {
  762.          fFirst = FALSE;
  763.  
  764.          if (bDoConvDLE)
  765.          {
  766.             pchSendBuff = achOutB;
  767.             ulSendBuffLen = ulSLen;
  768.          }
  769.          else
  770.          {
  771.             pchSendBuff = achFileB;
  772.             ulSendBuffLen = ulLen;
  773.          }
  774.  
  775.          usGlobalState=GS_INITPLAY;
  776.  
  777.          res = SendHayes2(ParamBlock.szATVoiceTX, 3000l, 1);
  778.          if (res)
  779.          {
  780.             SetComXONXOFF(FALSE, FALSE);
  781.             DosClose(fh);
  782.             prxsRet->strptr[0]='!';
  783.             return;
  784.          }
  785.       }
  786.       else
  787.       {
  788.          if (bDoConvDLE)
  789.          {
  790.             if (SendIt(achOutB, ulSLen))
  791.             {
  792.                if (fDebug)
  793.                   dprintf("Send error\n");
  794.                break;
  795.             }
  796.          }
  797.          else
  798.          {
  799.             if (SendIt(achFileB, ulLen))
  800.             {
  801.                if (fDebug)
  802.                   dprintf("Send error\n");
  803.                break;
  804.             }
  805.          }
  806.       }
  807.  
  808.       ulMsg=WaitQueue(IM_DLEFROMDCE | IM_STOP | IM_EXTUSER, &pData, &ulLen, SEM_IMMEDIATE_RETURN);
  809.       if (ulMsg)
  810.       {
  811.          switch (ulMsg)
  812.          {
  813.          case IM_DLEFROMDCE:
  814.             if (fDebug)
  815.                dprintf("Event %c\n", *((PCHAR)pData));
  816.             chRet=*((PCHAR)pData);
  817.             bOtherEvent=TRUE;
  818.             break;
  819.          case IM_EXTUSER:
  820.             if (fDebug)
  821.                dprintf("User event '%s' when playing voice\n", (PCHAR)pData);
  822.             strcpy(prxsRet->strptr, (PCHAR)pData);
  823.             prxsRet->strlength=strlen((PCHAR)pData);
  824.             chRet='\0';
  825.             bOtherEvent=TRUE;
  826.             break;
  827.          case IM_STOP:
  828.             if (fDebug)
  829.                dprintf("Playback STOPPED\n");
  830.             chRet='.';
  831.             bOtherEvent=TRUE;
  832.             break;
  833.          default:
  834.             bOtherEvent=TRUE;
  835.             chRet='!';
  836.          }
  837.  
  838.          free(pData);
  839.          SendHayes2(ParamBlock.szATVoiceCancelTX, 3000l, 3);
  840.          break;
  841.       }
  842.  
  843.       if (fAbortCmd)
  844.       {
  845.          if (fDebug)
  846.             dprintf("VTX aborted\n");
  847.          bOtherEvent=TRUE;
  848.          chRet='!';
  849.          break;
  850.       }
  851.    }
  852.  
  853.    SetComXONXOFF(FALSE, FALSE);
  854.    DosClose(fh);
  855.  
  856.    if (!bOtherEvent)
  857.    {
  858.       // See if any other events has occurred now
  859.       ulMsg=WaitQueue(IM_DLEFROMDCE | IM_EXTUSER, &pData, &ulLen, SEM_IMMEDIATE_RETURN);
  860.       if (ulMsg)
  861.       {
  862.          switch (ulMsg)
  863.          {
  864.          case IM_DLEFROMDCE:
  865.             if (fDebug)
  866.                dprintf("Event %c\n", *((PCHAR)pData));
  867.             chRet=*((PCHAR)pData);
  868.             bOtherEvent=TRUE;
  869.             break;
  870.          case IM_EXTUSER:
  871.             if (fDebug)
  872.                dprintf("User event '%s' when waiting for ETX\n", (PCHAR)pData);
  873.             strcpy(prxsRet->strptr, (PCHAR)pData);
  874.             prxsRet->strlength=strlen((PCHAR)pData);
  875.             chRet='\0';
  876.             bOtherEvent=TRUE;
  877.             break;
  878.          }
  879.          free(pData);
  880.       }
  881.    }
  882.  
  883.    if (fDebug)
  884.       dprintf("Playback ended\n");
  885.  
  886.    if (chRet)
  887.       prxsRet->strptr[0]=chRet;
  888. }
  889.  
  890.  
  891.  
  892. static USHORT StartRec
  893. (
  894.    USHORT usComp  // ZCOMP_*
  895. )
  896. {
  897.    ULONG ulLen;
  898.    CHAR szVSMCmd[MAXHAYESMSG];
  899.    ZYXHEAD zh;
  900.    USHORT res, usType;
  901.  
  902.    // Make sure the input queue is empty
  903.    ClearQueue(IM_STRFROMDCE | IM_DLEFROMDCE | IM_STOP, SEM_IMMEDIATE_RETURN);
  904.  
  905.    memset(&zh, 0, sizeof zh);
  906.  
  907.    switch (ParamBlock.szFileMode[0])
  908.    {
  909.    case 'Z':
  910.       if (usComp > 3)
  911.       {
  912.          bDLEConv = FALSE;
  913.          usType = usComp - 3;
  914.       }
  915.       else
  916.       {
  917.          bDLEConv = TRUE;
  918.          usType = usComp;
  919.       }
  920.       memcpy(&zh, achZyXKey, sizeof achZyXKey);
  921.       break;
  922.  
  923.    case 'G':
  924.       bDLEConv = FALSE;
  925.       usType = usComp;
  926.       memcpy(&zh, achAM4PMKey, sizeof achAM4PMKey);
  927.       break;
  928.  
  929.    default:
  930.       if (fDebug)
  931.          dprintf("Unkown file mode '%c'\n", ParamBlock.szFileMode[0]);
  932.       LogMessage(22, ParamBlock.szFileMode, NULL);
  933.       return 1;
  934.    }
  935.  
  936.    sprintf(szVSMCmd, ParamBlock.szATVoiceMode, usType);
  937.    res=SendHayes2(szVSMCmd, MAXWAITDCE, 1);
  938.    if (res)
  939.    {
  940.       if (fDebug)
  941.          dprintf("Send error %u\n", res);
  942.       return 1;
  943.    }
  944.  
  945.    if (hRec != 0)
  946.    {
  947.       // Write header
  948.       zh.usType=usComp-1;
  949.       DosWrite(hRec, &zh, sizeof zh, &ulLen);
  950.    }
  951.  
  952.    ulRecTime=0;
  953.  
  954.    SetComXONXOFF(FALSE, TRUE);
  955.  
  956.    usGlobalState=GS_INITREC;
  957.  
  958.    res=SendHayes2(ParamBlock.szATVoiceRX, 30000, 3);
  959.    if (res)
  960.       return 1;
  961.  
  962.    if (fDebug)
  963.       dprintf("Recording!\n");
  964.  
  965.    return 0;
  966.  
  967. }
  968.  
  969.  
  970. static USHORT EndRec(void)
  971. {
  972.    return SendHayes2("{VCON}", 3000, 3); // Anything will abort the recording
  973. }
  974.  
  975.  
  976. static void WaitDLECode
  977. (
  978.    ULONG ulTO,
  979.    PRXSTRING prxsRet
  980. )
  981. {
  982.    ULONG ulMsg, ulLen;
  983.    PVOID pData;
  984.    CHAR chRet;
  985.   
  986.    ulMsg=WaitQueue(IM_DLEFROMDCE | IM_ABORT | IM_STOP | IM_EXTUSER, &pData, &ulLen, ulTO);
  987.    if (ulMsg)
  988.    {
  989.       if (fAbortCmd)
  990.       {
  991.          if (fDebug)
  992.             dprintf("Receive aborted\n");
  993.          chRet='!';
  994.       }
  995.       else
  996.       {
  997.          switch (ulMsg)
  998.          {
  999.          case IM_DLEFROMDCE:
  1000.             if (fDebug)
  1001.                dprintf("Event %c\n", *((PCHAR)pData));
  1002.             chRet=*((PCHAR)pData);
  1003.             break;
  1004.  
  1005.          case IM_EXTUSER:
  1006.             if (fDebug)
  1007.                dprintf("User event '%s'\n", (PCHAR)pData);
  1008.             strcpy(prxsRet->strptr, (PCHAR)pData);
  1009.             prxsRet->strlength=strlen((PCHAR)pData);
  1010.             free(pData);
  1011.             return;
  1012. //          break;
  1013.  
  1014.          default:
  1015.             if (fDebug)
  1016.                dprintf("Receive stopped\n");
  1017.             chRet='.';
  1018.          }
  1019.       }
  1020.  
  1021.       if (ulMsg)
  1022.          free(pData);
  1023.    }
  1024.    else
  1025.    {
  1026.       if (fDebug)
  1027.          dprintf("Timeout\n");
  1028.       chRet='>';
  1029.    }
  1030.  
  1031.    prxsRet->strptr[0]=chRet;
  1032.    prxsRet->strlength=1;
  1033. }
  1034.  
  1035.  
  1036. static void WaitDCEResp
  1037. (
  1038.    ULONG ulTO,
  1039.    PRXSTRING prxsRet
  1040. )
  1041. {
  1042.    ULONG ulMsg, ulLen;
  1043.    PVOID pData;
  1044.    CHAR chRet;
  1045.   
  1046.    ulMsg=WaitQueue(IM_STRFROMDCE | IM_ABORT | IM_STOP, &pData, &ulLen, ulTO);
  1047.    if (ulMsg)
  1048.    {
  1049.       if (fAbortCmd)
  1050.       {
  1051.          if (fDebug)
  1052.             dprintf("Receive aborted\n");
  1053.          chRet='!';
  1054.       }
  1055.       else
  1056.       {
  1057.          switch (ulMsg)
  1058.          {
  1059.          case IM_STRFROMDCE:
  1060.             if (fDebug)
  1061.                dprintf("More DCE: '%s'\n", pData);
  1062.             strcpy(prxsRet->strptr, pData);
  1063.             prxsRet->strlength=strlen(pData);
  1064.             free(pData);
  1065.             return;
  1066.  
  1067.          default:
  1068.             if (fDebug)
  1069.                dprintf("Receive stopped\n");
  1070.             chRet='.';
  1071.          }
  1072.       }
  1073.  
  1074.       if (ulMsg)
  1075.          free(pData);
  1076.    }
  1077.    else
  1078.    {
  1079.       if (fDebug)
  1080.          dprintf("Timeout\n");
  1081.       chRet='>';
  1082.    }
  1083.  
  1084.    prxsRet->strptr[0]=chRet;
  1085.    prxsRet->strlength=1;
  1086. }
  1087.  
  1088.  
  1089. static void DoRelCom(BOOL fReset)
  1090. {
  1091.    PVOID pData;
  1092.    ULONG ulMsg, ulLen, ulCount;
  1093.  
  1094.    if (hCom)
  1095.    {
  1096.       WinPostMsg(hwndFrame, WMU_NOCOM, 0l, 0l);
  1097.       if (fDebug)
  1098.          dprintf("Releasing COM port\n");
  1099.  
  1100.       if (fReset)
  1101.       {
  1102.          SendHayes("ATZ\r");
  1103.          ulMsg=WaitQueue(IM_STRFROMDCE, &pData, &ulLen, MAXWAITDCE);
  1104.          if (ulMsg)
  1105.             free(pData);
  1106.       }
  1107.  
  1108.       DosResetEventSem(semStopedReading, &ulCount);
  1109.       DosPostEventSem(semStopRead);
  1110.       SetComTOZero();
  1111.       if (DosWaitEventSem(semStopedReading, 30000l))
  1112.          LogMessage(23, NULL); // Timeout waiting for reading thread
  1113.       SaveRestComMode(FALSE);
  1114.       DosClose(hCom);
  1115.       hCom=0l;
  1116.       DosReleaseMutexSem(semCom);
  1117.       WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup("COM port released")), 0l);
  1118.    }
  1119. }
  1120.  
  1121.  
  1122. static USHORT Wait4Call(void)
  1123. {
  1124.  
  1125.    USHORT res;
  1126.    ULONG ulMsg, ulLen, ulCrntTime;
  1127.    PVOID pData;
  1128.    CHAR szStr[10], *pch;
  1129.    BOOL fDeleteAborted;
  1130.    SHORT iRes;
  1131.    static ulRingTime=0l, ulRings=0l;
  1132.  
  1133.    // Empty queue
  1134.    ClearQueue(IM_STRFROMDCE | IM_DLEFROMDCE, 1000l);
  1135.  
  1136.    res=SendHayes("\r\r\r\r");
  1137.    if (res)
  1138.    {
  1139.       if (fDebug)
  1140.          dprintf("Send error %u\n", res);
  1141.       return res;
  1142.    }
  1143.  
  1144.    iRes=CallRexx("INIT.AMC", NULL);
  1145.    if (iRes)
  1146.    {
  1147.       if (fDebug)
  1148.          dprintf("Init error %u\n", iRes);
  1149.       return 0;
  1150.    }
  1151.  
  1152.    res=SendHayes("ATI\r");
  1153.    if (res)
  1154.    {
  1155.       if (fDebug)
  1156.          dprintf("Send error %u\n", res);
  1157.       return 0;
  1158.    }
  1159.  
  1160.    ulMsg=WaitQueue(IM_STRFROMDCE, &pData, &ulLen, MAXWAITDCE);
  1161.    if (ulMsg==IM_STRFROMDCE)
  1162.    {
  1163.       pszDCEVer=pData;
  1164.       if (fDebug)
  1165.          dprintf("ATI is '%s'\n", pData);
  1166.    }
  1167.  
  1168.    // Empty queue
  1169.    ClearQueue(IM_STRFROMDCE | IM_DLEFROMDCE, 1000l);
  1170.  
  1171.    for (; hCom;)
  1172.    {
  1173.       if (fAbortCmd)
  1174.       {
  1175.          for (fDeleteAborted=FALSE;;)
  1176.          {
  1177.             ulMsg=WaitQueue(0xffffffff, &pData, &ulLen, SEM_IMMEDIATE_RETURN);
  1178.             if (!ulMsg)
  1179.                break;
  1180.             free(pData);
  1181.             if (ulMsg==IM_DELETE)
  1182.                fDeleteAborted=TRUE;
  1183.                
  1184.          }
  1185.          if (fDeleteAborted)
  1186.             WinPostMsg(hwndFrame, WMU_UPDLIST, 0l, 0l);
  1187.          WinPostMsg(hwndFrame, WMU_LASTDCE, MPFROMP(strdup("Aborted")), 0l);
  1188.          fAbortCmd=FALSE;
  1189.       }
  1190.  
  1191.       WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup("Waiting for call")), 0l);
  1192.       if (fDebug)
  1193.          dprintf("Waiting for call\n");
  1194.  
  1195.       WinPostMsg(hwndFrame, WMU_IDLECMD, 0l, 0l);
  1196.       ulMsg=WaitQueue(0xffffffff, &pData, &ulLen, SEM_INDEFINITE_WAIT);
  1197.       if (fDebug)
  1198.          dprintf("Something happened. ulMsg=%lu\n", ulMsg);
  1199.       switch (ulMsg)
  1200.       {
  1201.          case IM_STRFROMDCE:
  1202.             if (strcmp(pData, "VCON")==0 || (ulLen >= 5 && memcmp(pData, "RING", 4)==0))
  1203.             {
  1204.                WinPostMsg(hwndFrame, WMU_BUSYCMD, 0l, 0l);
  1205.  
  1206.                ulCrntTime=GetSysMSecs();
  1207.  
  1208.                if (fDebug)
  1209.                   dprintf("Ring! Delay %lu\n", ulCrntTime-ulRingTime);
  1210.  
  1211.                if (ulCrntTime-ulRingTime >= MAXRINGDELAY)
  1212.                   ulRings=1;
  1213.                else
  1214.                   ulRings++;
  1215.  
  1216.                ulRingTime=ulCrntTime;
  1217.  
  1218.                iRes=CallRexx("RING.AMC", (PCHAR)pData, _ltoa(ulRings, szStr, 10), NULL);
  1219.                free(pData);
  1220.                WinPostMsg(hwndFrame, WMU_UPDLIST, 0l, 0l);
  1221.                switch (iRes)
  1222.                {
  1223.                case AMR_NORMAL:
  1224.                   res=HangUp();
  1225.                   if (res)
  1226.                      return 0;
  1227.                   break;
  1228.                case AMR_REINIT:
  1229.                   return 0;
  1230.                case AMR_EXIT:
  1231.                   return 1;
  1232.                default:
  1233.                   if (fDebug)
  1234.                      dprintf("Unkown return code from RING.AMC %i\n", iRes);
  1235.                   return 0;
  1236.                }
  1237.                break;
  1238.             }
  1239.             
  1240.             if (ulLen >= 5 && memcmp(pData, "TIME", 4)==0)
  1241.             {
  1242.                CallRexx("CID.AMC", pData, NULL);
  1243.                free(pData);
  1244.                break;
  1245.             }
  1246.             break;
  1247.  
  1248.          case IM_DOWN:
  1249.             free(pData);
  1250.             SendHayes("ATZ\r");
  1251.             ulMsg=WaitQueue(IM_STRFROMDCE, &pData, &ulLen, MAXWAITDCE);
  1252.             if (ulMsg)
  1253.                free(pData);
  1254.             return 1;
  1255.  
  1256.          case IM_PLAY:
  1257.             if (fDebug)
  1258.                dprintf("Request to play '%s'\n", pData);
  1259.             WinPostMsg(hwndFrame, WMU_BUSYCMD, 0l, 0l);
  1260.             iRes=CallRexx("PLAY.AMC", (PCHAR)pData, NULL);
  1261.             free(pData);
  1262. //          WinPostMsg(hwndFrame, WMU_UPDLIST, 0l, 0l);
  1263.             switch (iRes)
  1264.             {
  1265.             case AMR_NORMAL:
  1266.                res=HangUp();
  1267.                if (res)
  1268.                   return 0;
  1269.                break;
  1270.             case AMR_REINIT:
  1271.                return 0;
  1272.             case AMR_EXIT:
  1273.                return 1;
  1274.             default:
  1275.                if (fDebug)
  1276.                   dprintf("Unkown return code from PLAY.AMC %i\n", iRes);
  1277.                return 0;
  1278.             }
  1279.             break;
  1280.  
  1281.          case IM_DELETE:
  1282.             WinPostMsg(hwndFrame, WMU_BUSYCMD, 0l, 0l);
  1283.             if (fDebug)
  1284.                dprintf("Deleting '%s'\n", pData);
  1285.             iRes=CallRexx("DELETE.AMC", (PCHAR)pData, NULL);
  1286.             if (iRes==1)
  1287.                WinPostMsg(hwndFrame, WMU_UPDLIST, 0l, 0l);
  1288.             else
  1289.                ulRecMessages--;
  1290.             free(pData);
  1291.             break;
  1292.  
  1293.          case IM_RECORD:
  1294.             if (fDebug)
  1295.                dprintf("Request to record '%s'\n", pData);
  1296.             WinPostMsg(hwndFrame, WMU_BUSYCMD, 0l, 0l);
  1297.             iRes=CallRexx("RECORD.AMC", (PCHAR)pData, NULL);
  1298.             free(pData);
  1299. //          WinPostMsg(hwndFrame, WMU_UPDLIST, 0l, 0l);
  1300.             switch (iRes)
  1301.             {
  1302.             case AMR_NORMAL:
  1303.                res=HangUp();
  1304.                if (res)
  1305.                   return 0;
  1306.                break;
  1307.             case AMR_REINIT:
  1308.                return 0;
  1309.             case AMR_EXIT:
  1310.                return 1;
  1311.             default:
  1312.                if (fDebug)
  1313.                   dprintf("Unkown return code from RECORD.AMC %i\n", iRes);
  1314.                return 0;
  1315.             }
  1316.             break;
  1317.  
  1318.          case IM_RELEASE:
  1319.             free(pData);
  1320.             DoRelCom(TRUE);
  1321.             DosSleep(30000l);
  1322.             return 0;
  1323.  
  1324.          case IM_STARTAMC:
  1325.             WinPostMsg(hwndFrame, WMU_BUSYCMD, 0l, 0l);
  1326.             pch=strchr((PCHAR)pData, ' ');
  1327.             if (pch==NULL)
  1328.                pch="";
  1329.             else
  1330.             {
  1331.                *pch='\0';
  1332.                pch++;
  1333.             }
  1334.             iRes=CallRexx((PCHAR)pData, pch, NULL);
  1335.             free(pData);
  1336.             WinPostMsg(hwndFrame, WMU_UPDLIST, 0l, 0l);
  1337.             switch (iRes)
  1338.             {
  1339.             case AMR_NORMAL:
  1340.                res=HangUp();
  1341.                if (res)
  1342.                   return 0;
  1343.                break;
  1344.             case AMR_REINIT:
  1345.                return 0;
  1346.             case AMR_EXIT:
  1347.                return 1;
  1348.             default:
  1349.                if (fDebug)
  1350.                   dprintf("Unkown return code from AMC script %i\n", iRes);
  1351.                return 0;
  1352.             }
  1353.             break;
  1354.  
  1355.          case IM_EXTUSER:
  1356.             WinPostMsg(hwndFrame, WMU_BUSYCMD, 0l, 0l);
  1357.             iRes=CallRexx("USER.AMC", (PCHAR)pData, NULL);
  1358.             free(pData);
  1359.             WinPostMsg(hwndFrame, WMU_UPDLIST, 0l, 0l);
  1360.             switch (iRes)
  1361.             {
  1362.             case AMR_NORMAL:
  1363.                res=HangUp();
  1364.                if (res)
  1365.                   return 0;
  1366.                break;
  1367.             case AMR_REINIT:
  1368.                return 0;
  1369.             case AMR_EXIT:
  1370.                return 1;
  1371.             default:
  1372.                if (fDebug)
  1373.                   dprintf("Unkown return code from USER.AMC %i\n", iRes);
  1374.                return 0;
  1375.             }
  1376.             break;
  1377.  
  1378.          case IM_INICHANGED:
  1379.             return 0;
  1380.  
  1381.          default:
  1382.             free(pData);
  1383.       }
  1384.    }
  1385.  
  1386.    return 0;
  1387. }
  1388.  
  1389.  
  1390. static void makeit(void)
  1391. {
  1392.    ULONG ulCount;
  1393.    USHORT res;
  1394.    static BOOL fFirst=TRUE;
  1395.  
  1396.  
  1397.    for (;;)
  1398.    {
  1399.       WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup("Initializing")), 0l);
  1400.       GetIniFile();
  1401.  
  1402.       res=OpenCom();
  1403.       if (res)
  1404.       {
  1405.          WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup("Cannot open COM")), 0l);
  1406.          DosSleep(WAITRETRYCOM);
  1407.          continue;
  1408.       }
  1409.       if (fFirst)
  1410.       {
  1411.          fFirst=FALSE;
  1412.          SaveRestComMode(TRUE);
  1413.       }
  1414.       SetComMode();
  1415.  
  1416.       usGlobalState=GS_READY;
  1417.       DosPostEventSem(semGoOnRead);
  1418.  
  1419.       res=Wait4Call();
  1420.  
  1421.       if (res)
  1422.          CallRexx("EXIT.AMC", hCom ? "1" : "0", NULL);
  1423.  
  1424.       WriteState2IniFile();
  1425.  
  1426.       if (hCom)
  1427.       {
  1428.          DosResetEventSem(semStopedReading, &ulCount);
  1429.          DosPostEventSem(semStopRead);
  1430.          SetComTOZero();
  1431.          if (DosWaitEventSem(semStopedReading, 30000l))
  1432.             LogMessage(23, NULL); // Timeout waiting for reading thread
  1433.       }
  1434.  
  1435.       if (res)
  1436.          return;
  1437.  
  1438.       if (hCom)
  1439.       {
  1440. //       SaveRestComMode(FALSE);
  1441.          DosClose(hCom);
  1442.          hCom=0l;
  1443.          DosReleaseMutexSem(semCom);
  1444.       }
  1445.  
  1446.       DosSleep(2500l);
  1447.    }
  1448. }
  1449.  
  1450.  
  1451. USHORT StartProg
  1452. (
  1453.    PCHAR szCmdLine,
  1454.    PUSHORT pusRetCode
  1455. )
  1456. {
  1457.    ULONG res, i, ulLen, ulSid;
  1458.    PID pid;
  1459.    CHAR szInput[45], szExeFile[255], szProg[40], bPriority;
  1460.    STARTDATA StartData;
  1461.    PCHAR pszArg;
  1462.    HQUEUE hQ;
  1463.    static CHAR szQN[]="\\queues\\am4pm\\startp";
  1464.    REQUESTDATA rd;
  1465.    PVOID pData;
  1466.  
  1467.    // Find EXE file
  1468.    for (i=0; i < sizeof szProg - 1 && szCmdLine[i] != ' ' && szCmdLine[i] != '\0'; i++)
  1469.       szProg[i]=szCmdLine[i];
  1470.    szProg[i]='\0';
  1471.  
  1472.    pszArg=szCmdLine+i;
  1473.    if (szCmdLine[i] != '\0')
  1474.       pszArg++;
  1475.  
  1476.    strcpy(szInput, szProg),
  1477.    strcat(szInput, ".EXE");
  1478.  
  1479.    res=DosSearchPath(SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY, "PATH", szInput, szExeFile, 255);
  1480.    if (res)
  1481.       return res;
  1482.  
  1483.    if (fDebug)
  1484.       dprintf("Starting '%s' '%s'\n", szExeFile, pszArg);
  1485.  
  1486.    StartData.Length=50; // sizeof StartData;
  1487.    StartData.Related=SSF_RELATED_CHILD;
  1488.    StartData.FgBg=SSF_FGBG_BACK;
  1489.    StartData.TraceOpt=SSF_TRACEOPT_NONE;
  1490.    StartData.PgmTitle=NULL;
  1491.    StartData.PgmName=szExeFile;
  1492.    StartData.PgmInputs=pszArg;
  1493.    StartData.TermQ=szQN;
  1494.    StartData.Environment=NULL;
  1495.    StartData.InheritOpt=SSF_INHERTOPT_PARENT;
  1496.    StartData.SessionType=SSF_TYPE_FULLSCREEN;
  1497.    StartData.IconFile=NULL;
  1498.    StartData.PgmHandle=0l;
  1499. // if (fDebug)
  1500. //    StartData.PgmControl=SSF_CONTROL_VISIBLE | SSF_CONTROL_NOAUTOCLOSE;
  1501. // else
  1502.       StartData.PgmControl=SSF_CONTROL_VISIBLE | SSF_CONTROL_MINIMIZE;
  1503.  
  1504.    res=DosCreateQueue(&hQ, QUE_FIFO, szQN);
  1505.    if (res)
  1506.    {
  1507.       if (fDebug)
  1508.          dprintf("Error %u creating queue\n", res);
  1509.       return res;
  1510.    }
  1511.  
  1512.    res=DosStartSession(&StartData, &ulSid, &pid);
  1513.    if (res && res!=ERROR_SMG_START_IN_BACKGROUND)
  1514.    {
  1515.       if (fDebug)
  1516.          dprintf("Error %u starting session\n", res);
  1517.       DosCloseQueue(hQ);
  1518.       return res;
  1519.    }
  1520.  
  1521.    res=DosReadQueue(hQ, &rd, &ulLen, &pData, 0, DCWW_WAIT, &bPriority, 0l);
  1522.    DosCloseQueue(hQ);
  1523.    if (res)
  1524.    {
  1525.       if (fDebug)
  1526.          dprintf("Error %u reading queue\n", res);
  1527.       return res;
  1528.    }
  1529.  
  1530.    *pusRetCode=((PUSHORT)pData)[1];
  1531.  
  1532.    DosFreeMem(pData);
  1533.  
  1534.    DosCloseQueue(hQ);
  1535.    return 0;
  1536. }
  1537.  
  1538.  
  1539. static signed _System AMGetHotComm
  1540. (
  1541.    PSZ pszName,
  1542.    ULONG ulArgc,
  1543.    RXSTRING arxsArgv[],
  1544.    PSZ pszQueueName,
  1545.    PRXSTRING prxsRet
  1546. )
  1547. {
  1548.    ULONG ulCount;
  1549.  
  1550.    if (ulArgc != 0)
  1551.    {
  1552.       LogMessage(13, pszName, NULL);
  1553.       if (fDebug)
  1554.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1555.       return 1;
  1556.    }
  1557.  
  1558.    DosResetEventSem(semStopedReading, &ulCount);
  1559.    DosPostEventSem(semStopRead);
  1560.    SetComTOZero();
  1561.    if (DosWaitEventSem(semStopedReading, 30000l))
  1562.       LogMessage(23, NULL); // Timeout waiting for reading thread
  1563.    SaveRestComMode(FALSE);
  1564.    _ltoa((ULONG)hCom, prxsRet->strptr, 10);
  1565.    prxsRet->strlength=strlen(prxsRet->strptr);
  1566.  
  1567.    return 0;
  1568. }
  1569.  
  1570.  
  1571. static signed _System AMReleaseHotComm
  1572. (
  1573.    PSZ pszName,
  1574.    ULONG ulArgc,
  1575.    RXSTRING arxsArgv[],
  1576.    PSZ pszQueueName,
  1577.    PRXSTRING prxsRet
  1578. )
  1579. {
  1580.    if (ulArgc != 0)
  1581.    {
  1582.       LogMessage(13, pszName, NULL);
  1583.       if (fDebug)
  1584.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1585.       return 1;
  1586.    }
  1587.  
  1588.    SetComMode();
  1589.  
  1590.    DosPostEventSem(semGoOnRead);
  1591.  
  1592.    prxsRet->strptr=NULL;
  1593.  
  1594.    return 0;
  1595. }
  1596.  
  1597.  
  1598. static signed _System AMDPrint
  1599. (
  1600.    PSZ pszName,
  1601.    ULONG ulArgc,
  1602.    RXSTRING arxsArgv[],
  1603.    PSZ pszQueueName,
  1604.    PRXSTRING prxsRet
  1605. )
  1606. {
  1607.    if (ulArgc != 1)
  1608.    {
  1609.       LogMessage(13, pszName, NULL);
  1610.       if (fDebug)
  1611.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1612.       return 1;
  1613.    }
  1614.  
  1615.    dprintf("DPRINT '%s'\n", arxsArgv[0].strptr);
  1616.  
  1617.    prxsRet->strptr=NULL;
  1618.  
  1619.    return 0;
  1620. }
  1621.  
  1622.  
  1623. static signed _System AMLog
  1624. (
  1625.    PSZ pszName,
  1626.    ULONG ulArgc,
  1627.    RXSTRING arxsArgv[],
  1628.    PSZ pszQueueName,
  1629.    PRXSTRING prxsRet
  1630. )
  1631. {
  1632.    if (ulArgc != 1)
  1633.    {
  1634.       LogMessage(13, pszName, NULL);
  1635.       if (fDebug)
  1636.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1637.       return 1;
  1638.    }
  1639.  
  1640.    LogMessage(21, arxsArgv[0].strptr, NULL);
  1641.  
  1642.    prxsRet->strptr=NULL;
  1643.  
  1644.    return 0;
  1645. }
  1646.  
  1647.  
  1648. static signed _System AMOpenRecFile
  1649. (
  1650.    PSZ pszName,
  1651.    ULONG ulArgc,
  1652.    RXSTRING arxsArgv[],
  1653.    PSZ pszQueueName,
  1654.    PRXSTRING prxsRet
  1655. )
  1656. {
  1657.    if (ulArgc != 0)
  1658.    {
  1659.       LogMessage(13, pszName, NULL);
  1660.       if (fDebug)
  1661.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1662.       return 1;
  1663.    }
  1664.  
  1665.    hRec=CreateMFile();
  1666.    strcpy(prxsRet->strptr, szCrntMFile);
  1667.  
  1668.    prxsRet->strlength=strlen(prxsRet->strptr);
  1669.  
  1670.    return 0;
  1671. }
  1672.  
  1673.  
  1674. static void WriteEA
  1675. (
  1676.    HFILE fh,
  1677.    CHAR const * szEA,
  1678.    USHORT usEAType,
  1679.    PVOID pEAData,
  1680.    USHORT usDLen
  1681. )
  1682. {
  1683.    USHORT usEA2Len;
  1684.    EAOP2 eaop2;
  1685.    PFEA2LIST pfea2list;
  1686.    APIRET rc;
  1687.  
  1688.  
  1689.    usEA2Len=sizeof *pfea2list + strlen(szEA);
  1690.  
  1691.    pfea2list=malloc(usEA2Len + usDLen + 2*sizeof(USHORT));
  1692.  
  1693.    memcpy((PCHAR)pfea2list + usEA2Len + 2*sizeof(USHORT), pEAData, usDLen);
  1694.    *(PUSHORT)((PCHAR)pfea2list + usEA2Len) = usEAType;
  1695.    *(PUSHORT)((PCHAR)pfea2list + usEA2Len + sizeof (USHORT)) = usDLen;
  1696.  
  1697.    pfea2list->cbList=sizeof(FEA2) + strlen(szEA) + usDLen + 2*sizeof(USHORT);
  1698.    pfea2list->list[0].oNextEntryOffset=0;
  1699.    pfea2list->list[0].fEA=0;
  1700.    pfea2list->list[0].cbName=strlen(szEA);
  1701.    pfea2list->list[0].cbValue=usDLen + 2*sizeof(USHORT);
  1702.    strcpy(pfea2list->list[0].szName, szEA);
  1703.  
  1704.    eaop2.fpFEA2List=pfea2list;
  1705.    rc=DosSetFileInfo(fh, FIL_QUERYEASIZE, &eaop2, sizeof eaop2);
  1706.    free(pfea2list);
  1707.  
  1708.    if (fDebug && rc != NO_ERROR)
  1709.       dprintf("Error %lu setting EA\n", rc);
  1710. }
  1711.  
  1712.  
  1713. static signed _System AMCloseRecFile
  1714. (
  1715.    PSZ pszName,
  1716.    ULONG ulArgc,
  1717.    RXSTRING arxsArgv[],
  1718.    PSZ pszQueueName,
  1719.    PRXSTRING prxsRet
  1720. )
  1721. {
  1722.    ULONG ulTime;
  1723.  
  1724.    if (ulArgc != 0)
  1725.    {
  1726.       LogMessage(13, pszName, NULL);
  1727.       if (fDebug)
  1728.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1729.       return 1;
  1730.    }
  1731.  
  1732.    if (fDebug)
  1733.       dprintf("Recording lasted %lu s\n", ulRecTime/1000);
  1734.  
  1735.    ulTime=ulRecTime/1000;
  1736.    WriteEA(hRec, szEALen, EAT_BINARY, &ulTime, sizeof ulTime);
  1737.    WriteEA(hRec, szEAType, EAT_ASCII, szOurEAType, strlen(szOurEAType));
  1738.  
  1739.    DosClose(hRec);
  1740.  
  1741.    prxsRet->strptr=NULL;
  1742.  
  1743.    return 0;
  1744. }
  1745.  
  1746.  
  1747. static signed _System AMPlayFile
  1748. (
  1749.    PSZ pszName,
  1750.    ULONG ulArgc,
  1751.    RXSTRING arxsArgv[],
  1752.    PSZ pszQueueName,
  1753.    PRXSTRING prxsRet
  1754. )
  1755. {
  1756.    if (ulArgc < 1 || ulArgc > 2)
  1757.    {
  1758.       LogMessage(13, pszName, NULL);
  1759.       if (fDebug)
  1760.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1761.       return 1;
  1762.    }
  1763.  
  1764.    if (ulArgc >= 2)
  1765.       strncpy((PCHAR)szActiveDLECodes, arxsArgv[1].strptr, sizeof szActiveDLECodes - 1);
  1766.    else
  1767.       szActiveDLECodes[0] = '\0';
  1768.  
  1769.    PlayFile(prxsRet, arxsArgv[0].strptr);
  1770.    return 0;
  1771. }
  1772.  
  1773.  
  1774. static signed _System AMStartRec
  1775. (
  1776.    PSZ pszName,
  1777.    ULONG ulArgc,
  1778.    RXSTRING arxsArgv[],
  1779.    PSZ pszQueueName,
  1780.    PRXSTRING prxsRet
  1781. )
  1782. {
  1783.    if (ulArgc != 1)
  1784.    {
  1785.       LogMessage(13, pszName, NULL);
  1786.       if (fDebug)
  1787.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1788.       return 1;
  1789.    }
  1790.  
  1791.    prxsRet->strptr=NULL;
  1792.  
  1793.    if (StartRec(atoi(arxsArgv[0].strptr)))
  1794.       return 2;
  1795.    return 0;
  1796. }
  1797.  
  1798.  
  1799. static signed _System AMEndListenDLECode
  1800. (
  1801.    PSZ pszName,
  1802.    ULONG ulArgc,
  1803.    RXSTRING arxsArgv[],
  1804.    PSZ pszQueueName,
  1805.    PRXSTRING prxsRet
  1806. )
  1807. {
  1808.    if (ulArgc != 0)
  1809.    {
  1810.       LogMessage(13, pszName, NULL);
  1811.       if (fDebug)
  1812.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1813.       return 1;
  1814.    }
  1815.  
  1816.    prxsRet->strptr=NULL;
  1817.  
  1818.    if (EndRec())
  1819.       return 2;
  1820.    return 0;
  1821. }
  1822.  
  1823.  
  1824. static signed _System AMEndRec
  1825. (
  1826.    PSZ pszName,
  1827.    ULONG ulArgc,
  1828.    RXSTRING arxsArgv[],
  1829.    PSZ pszQueueName,
  1830.    PRXSTRING prxsRet
  1831. )
  1832. {
  1833.    if (ulArgc != 0)
  1834.    {
  1835.       LogMessage(13, pszName, NULL);
  1836.       if (fDebug)
  1837.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1838.       return 1;
  1839.    }
  1840.  
  1841.    prxsRet->strptr=NULL;
  1842.  
  1843.    if (EndRec())
  1844.       return 2;
  1845.    return 0;
  1846. }
  1847.  
  1848.  
  1849. static signed _System AMCloseComm
  1850. (
  1851.    PSZ pszName,
  1852.    ULONG ulArgc,
  1853.    RXSTRING arxsArgv[],
  1854.    PSZ pszQueueName,
  1855.    PRXSTRING prxsRet
  1856. )
  1857. {
  1858.    if (ulArgc != 0)
  1859.    {
  1860.       LogMessage(13, pszName, NULL);
  1861.       if (fDebug)
  1862.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1863.       return 1;
  1864.    }
  1865.  
  1866.    DoRelCom(FALSE);
  1867.  
  1868.    strcpy(prxsRet->strptr, ParamBlock.szCom);
  1869.    prxsRet->strlength=strlen(ParamBlock.szCom);
  1870.  
  1871.    return 0;
  1872. }
  1873.  
  1874.  
  1875. static signed _System AMOpenComm
  1876. (
  1877.    PSZ pszName,
  1878.    ULONG ulArgc,
  1879.    RXSTRING arxsArgv[],
  1880.    PSZ pszQueueName,
  1881.    PRXSTRING prxsRet
  1882. )
  1883. {
  1884.    ULONG i, res;
  1885.  
  1886.    if (ulArgc != 0)
  1887.    {
  1888.       LogMessage(13, pszName, NULL);
  1889.       if (fDebug)
  1890.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1891.       return 1;
  1892.    }
  1893.  
  1894.    if (fDebug)
  1895.       dprintf("Opening COM port again\n");
  1896.  
  1897.    for (i=0; i<400; i++)
  1898.    {
  1899.       WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup("Opening COM")), 0l);
  1900.       res=OpenCom();
  1901.       if (res)
  1902.       {
  1903.          WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup("Waiting for COM")), 0l);
  1904.          DosSleep(WAITRETRYCOM);
  1905.          continue;
  1906.       }
  1907.       SetComMode();
  1908.       prxsRet->strptr=NULL;
  1909.  
  1910.       WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup("")), 0l);
  1911.  
  1912.       if (fDebug)
  1913.          dprintf("COM port opened again\n");
  1914.  
  1915.       return 0;
  1916.    }
  1917.  
  1918.    return 2;
  1919. }
  1920.  
  1921.  
  1922. static signed _System AMStartListenDLECode
  1923. (
  1924.    PSZ pszName,
  1925.    ULONG ulArgc,
  1926.    RXSTRING arxsArgv[],
  1927.    PSZ pszQueueName,
  1928.    PRXSTRING prxsRet
  1929. )
  1930. {
  1931.    USHORT usMode=2;
  1932.  
  1933.    if (ulArgc > 0)
  1934.    {
  1935.       if (ulArgc == 1)
  1936.          usMode=atoi(arxsArgv[0].strptr);
  1937.       else
  1938.       {
  1939.          LogMessage(13, pszName, NULL);
  1940.          if (fDebug)
  1941.             dprintf("Bad number of arguments in '%s'\n", pszName);
  1942.          return 1;
  1943.       }
  1944.    }
  1945.  
  1946.    hRec=0;
  1947.  
  1948.    prxsRet->strptr=NULL;
  1949.  
  1950.    if (StartRec(usMode))
  1951.       return 2;
  1952.    return 0;
  1953. }
  1954.  
  1955.  
  1956. static signed _System AMWaitDLECode
  1957. (
  1958.    PSZ pszName,
  1959.    ULONG ulArgc,
  1960.    RXSTRING arxsArgv[],
  1961.    PSZ pszQueueName,
  1962.    PRXSTRING prxsRet
  1963. )
  1964. {
  1965.    ULONG ulTO;
  1966.  
  1967.    if (ulArgc > 2)
  1968.    {
  1969.       LogMessage(13, pszName, NULL);
  1970.       if (fDebug)
  1971.          dprintf("Bad number of arguments in '%s'\n", pszName);
  1972.       return 1;
  1973.    }
  1974.  
  1975.    if (ulArgc >= 1)
  1976.       ulTO = atol(arxsArgv[0].strptr);
  1977.    else
  1978.       ulTO = 120000l;
  1979.  
  1980.    if (ulArgc >= 2)
  1981.       strncpy((PCHAR)szActiveDLECodes, arxsArgv[1].strptr, sizeof szActiveDLECodes - 1);
  1982.    else
  1983.       szActiveDLECodes[0] = '\0';
  1984.  
  1985.    WaitDLECode(ulTO, prxsRet);
  1986.  
  1987.    return 0;
  1988. }
  1989.  
  1990.  
  1991. static signed _System AMSendW
  1992. (
  1993.    PSZ pszName,
  1994.    ULONG ulArgc,
  1995.    RXSTRING arxsArgv[],
  1996.    PSZ pszQueueName,
  1997.    PRXSTRING prxsRet
  1998. )
  1999. {
  2000.    CHAR szHayes[256];
  2001.    ULONG ulMsg, ulLen;
  2002.    PVOID pData;
  2003.  
  2004.    if (ulArgc != 1)
  2005.    {
  2006.       LogMessage(13, pszName, NULL);
  2007.       if (fDebug)
  2008.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2009.       return 1;
  2010.    }
  2011.  
  2012.    // Make sure the input queue is empty
  2013.    WaitQueue(0, &pData, &ulLen, SEM_IMMEDIATE_RETURN);
  2014.  
  2015.    if (fDebug)
  2016.       dprintf("Sending '%s'\n", arxsArgv[0].strptr);
  2017.    strcpy(szHayes, arxsArgv[0].strptr);
  2018.    strcat(szHayes, "\r");
  2019.    if (SendHayes(szHayes))
  2020.       return 2;
  2021.  
  2022.    ulMsg=WaitQueue(IM_STRFROMDCE, &pData, &ulLen, MAXWAITDCE);
  2023.    if (ulMsg!=IM_STRFROMDCE)
  2024.    {
  2025.       strcpy(prxsRet->strptr, "!");
  2026.       prxsRet->strlength=1;
  2027.    }
  2028.    else
  2029.    {
  2030.       if (fDebug)
  2031.          dprintf("DCE returned '%s'\n", pData);
  2032.  
  2033.       strcpy(prxsRet->strptr, pData);
  2034.       prxsRet->strlength=strlen(pData);
  2035.    }
  2036.  
  2037.    if (ulMsg)
  2038.       free(pData);
  2039.  
  2040.    return 0;
  2041. }
  2042.  
  2043.  
  2044. static signed _System AMSendAT
  2045. (
  2046.    PSZ pszName,
  2047.    ULONG ulArgc,
  2048.    RXSTRING arxsArgv[],
  2049.    PSZ pszQueueName,
  2050.    PRXSTRING prxsRet
  2051. )
  2052. {
  2053.    ULONG ulTO = MAXWAITDCE;
  2054.    USHORT usRetries = 1;
  2055.  
  2056.    prxsRet->strptr=NULL;
  2057.  
  2058.    if (ulArgc > 3 || ulArgc < 1)
  2059.    {
  2060.       LogMessage(13, pszName, NULL);
  2061.       if (fDebug)
  2062.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2063.       return 1;
  2064.    }
  2065.  
  2066.    if (ulArgc >= 3)
  2067.       usRetries = atoi(arxsArgv[2].strptr);
  2068.  
  2069.    if (ulArgc >= 2)
  2070.       ulTO = atol(arxsArgv[1].strptr);
  2071.  
  2072.    return SendHayes2(arxsArgv[0].strptr, ulTO, usRetries) ? 2 : 0;
  2073. }
  2074.  
  2075.  
  2076. static signed _System AMGetMoreDCEResp
  2077. (
  2078.    PSZ pszName,
  2079.    ULONG ulArgc,
  2080.    RXSTRING arxsArgv[],
  2081.    PSZ pszQueueName,
  2082.    PRXSTRING prxsRet
  2083. )
  2084. {
  2085.    ULONG ulTO = MAXWAITDCE;
  2086.  
  2087.    if (ulArgc > 0)
  2088.    {
  2089.       if (ulArgc == 1)
  2090.          ulTO = atol(arxsArgv[0].strptr);
  2091.       else
  2092.       {
  2093.          LogMessage(13, pszName, NULL);
  2094.          if (fDebug)
  2095.             dprintf("Bad number of arguments in '%s'\n", pszName);
  2096.          return 1;
  2097.       }
  2098.    }
  2099.  
  2100.    WaitDCEResp(ulTO, prxsRet);
  2101.  
  2102.    #if 0
  2103.    ULONG ulMsg, ulLen;
  2104.    PVOID pData;
  2105.    ulMsg=WaitQueue(IM_STRFROMDCE, &pData, &ulLen, ulTO);
  2106.    if (ulMsg!=IM_STRFROMDCE)
  2107.    {
  2108.       if (ulMsg)
  2109.          free(pData);
  2110.       return 2;
  2111.    }
  2112.  
  2113.    if (fDebug)
  2114.       dprintf("DCE returned '%s'\n", pData);
  2115.    strcpy(prxsRet->strptr, pData);
  2116.    prxsRet->strlength=strlen(pData);
  2117.  
  2118.    free(pData);
  2119.    #endif
  2120.  
  2121.    return 0;
  2122. }
  2123.  
  2124.  
  2125. static signed _System AMStartProg
  2126. (
  2127.    PSZ pszName,
  2128.    ULONG ulArgc,
  2129.    RXSTRING arxsArgv[],
  2130.    PSZ pszQueueName,
  2131.    PRXSTRING prxsRet
  2132. )
  2133. {
  2134.    USHORT res, usRetCode;
  2135.  
  2136.    if (ulArgc != 1)
  2137.    {
  2138.       LogMessage(13, pszName, NULL);
  2139.       if (fDebug)
  2140.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2141.       return 1;
  2142.    }
  2143.  
  2144.    res=StartProg(arxsArgv[0].strptr, &usRetCode);
  2145.    if (res)
  2146.    {
  2147.       if (fDebug)
  2148.          dprintf("Error %u starting '%s'\n", res, arxsArgv[0].strptr);
  2149.       LogNumMessage(9, res, arxsArgv[0].strptr, NULL);
  2150.       return 2;
  2151.    }
  2152.  
  2153.    _itoa(usRetCode, prxsRet->strptr, 10);
  2154.    prxsRet->strlength=strlen(prxsRet->strptr);
  2155.  
  2156.    return 0;
  2157. }
  2158.  
  2159.  
  2160. static signed _System AMSetStateText
  2161. (
  2162.    PSZ pszName,
  2163.    ULONG ulArgc,
  2164.    RXSTRING arxsArgv[],
  2165.    PSZ pszQueueName,
  2166.    PRXSTRING prxsRet
  2167. )
  2168. {
  2169.    if (ulArgc != 1)
  2170.    {
  2171.       LogMessage(13, pszName, NULL);
  2172.       if (fDebug)
  2173.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2174.       return 1;
  2175.    }
  2176.  
  2177.    WinPostMsg(hwndFrame, WMU_STATE, MPFROMP(strdup(arxsArgv[0].strptr)), 0l);
  2178.  
  2179.    prxsRet->strptr=NULL;
  2180.  
  2181.    return 0;
  2182. }
  2183.  
  2184.  
  2185. static signed _System AMSetLastEventText
  2186. (
  2187.    PSZ pszName,
  2188.    ULONG ulArgc,
  2189.    RXSTRING arxsArgv[],
  2190.    PSZ pszQueueName,
  2191.    PRXSTRING prxsRet
  2192. )
  2193. {
  2194.    if (ulArgc != 1)
  2195.    {
  2196.       LogMessage(13, pszName, NULL);
  2197.       if (fDebug)
  2198.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2199.       return 1;
  2200.    }
  2201.  
  2202.    WinPostMsg(hwndFrame, WMU_LASTDCE, MPFROMP(strdup(arxsArgv[0].strptr)), 0l);
  2203.  
  2204.    prxsRet->strptr=NULL;
  2205.  
  2206.    return 0;
  2207. }
  2208.  
  2209.  
  2210. static signed _System AMReadIni
  2211. (
  2212.    PSZ pszName,
  2213.    ULONG ulArgc,
  2214.    RXSTRING arxsArgv[],
  2215.    PSZ pszQueueName,
  2216.    PRXSTRING prxsRet
  2217. )
  2218. {
  2219.    PCHAR psz;
  2220.  
  2221.    if (ulArgc != 2)
  2222.    {
  2223.       LogMessage(13, pszName, NULL);
  2224.       if (fDebug)
  2225.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2226.       return 1;
  2227.    }
  2228.  
  2229.    psz=IniGetSZ(arxsArgv[0].strptr, arxsArgv[1].strptr);
  2230.  
  2231.    strcpy(prxsRet->strptr, psz);
  2232.    prxsRet->strlength=strlen(psz);
  2233.    free(psz);
  2234.    return 0;
  2235. }
  2236.  
  2237.  
  2238. static signed _System AMWriteIni
  2239. (
  2240.    PSZ pszName,
  2241.    ULONG ulArgc,
  2242.    RXSTRING arxsArgv[],
  2243.    PSZ pszQueueName,
  2244.    PRXSTRING prxsRet
  2245. )
  2246. {
  2247.    if (ulArgc != 2)
  2248.    {
  2249.       LogMessage(13, pszName, NULL);
  2250.       if (fDebug)
  2251.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2252.       return 1;
  2253.    }
  2254.  
  2255.    IniPutSZ(arxsArgv[0].strptr, arxsArgv[1].strptr);
  2256.  
  2257.    prxsRet->strptr=NULL;
  2258.  
  2259.    return 0;
  2260. }
  2261.  
  2262. static void GetIOAccess(void)
  2263. {
  2264.    int rc;
  2265.    static BOOL bAccess=FALSE;
  2266.  
  2267.    if (!bAccess)
  2268.    {
  2269.       rc=Dos16PortAccess(0,0,0x000,0xFFF);
  2270.       if (rc)
  2271.          LogDosMessage(rc, 16, NULL);
  2272.       else
  2273.          bAccess = TRUE;
  2274.       if (fDebug)
  2275.          dprintf("DosPortAccess=%u\n", rc);
  2276.    }
  2277. }
  2278.  
  2279. static signed _System AMInp
  2280. (
  2281.    PSZ pszName,
  2282.    ULONG ulArgc,
  2283.    RXSTRING arxsArgv[],
  2284.    PSZ pszQueueName,
  2285.    PRXSTRING prxsRet
  2286. )
  2287. {
  2288.    USHORT usPort, usData;
  2289.  
  2290.    if (ulArgc != 1)
  2291.    {
  2292.       LogMessage(13, pszName, NULL);
  2293.       if (fDebug)
  2294.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2295.       return 1;
  2296.    }
  2297.  
  2298.    usPort = atoi(arxsArgv[0].strptr);
  2299.    GetIOAccess();
  2300.  
  2301.    usData = RPORT(usPort);
  2302.  
  2303.    itoa(usData, prxsRet->strptr, 10);
  2304.    prxsRet->strlength=strlen(prxsRet->strptr);
  2305.  
  2306.    return 0;
  2307. }
  2308.  
  2309.  
  2310. static signed _System AMOutp
  2311. (
  2312.    PSZ pszName,
  2313.    ULONG ulArgc,
  2314.    RXSTRING arxsArgv[],
  2315.    PSZ pszQueueName,
  2316.    PRXSTRING prxsRet
  2317. )
  2318. {
  2319.    USHORT usPort, usData;
  2320.  
  2321.    if (ulArgc != 2)
  2322.    {
  2323.       LogMessage(13, pszName, NULL);
  2324.       if (fDebug)
  2325.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2326.       return 1;
  2327.    }
  2328.  
  2329.    usPort = atoi(arxsArgv[0].strptr);
  2330.    usData = atoi(arxsArgv[1].strptr);
  2331.    GetIOAccess();
  2332.  
  2333.    WPORT(usPort, usData);
  2334.  
  2335.    prxsRet->strptr=NULL;
  2336.    return 0;
  2337. }
  2338.  
  2339.  
  2340. static signed _System AMTrimFileEnd
  2341. (
  2342.    PSZ pszName,
  2343.    ULONG ulArgc,
  2344.    RXSTRING arxsArgv[],
  2345.    PSZ pszQueueName,
  2346.    PRXSTRING prxsRet
  2347. )
  2348. {
  2349.    ULONG ulBytes;
  2350.    FILESTATUS3 fs;
  2351.    APIRET res;
  2352.  
  2353.    if (ulArgc != 1)
  2354.    {
  2355.       LogMessage(13, pszName, NULL);
  2356.       if (fDebug)
  2357.          dprintf("Bad number of arguments in '%s'\n", pszName);
  2358.       return 1;
  2359.    }
  2360.  
  2361.    ulBytes = atol(arxsArgv[0].strptr);
  2362.  
  2363.    if (hRec == 0l)
  2364.    {
  2365.       LogMessage(19, NULL);   // No file open for recording
  2366.       return 2;
  2367.    }
  2368.  
  2369.    res = DosQueryFileInfo(hRec, FIL_STANDARD, &fs, sizeof fs);
  2370.    if (res)
  2371.    {
  2372.       LogDosMessage(res, 17, NULL);
  2373.       return 2;
  2374.    }
  2375.  
  2376.    if ((LONG)fs.cbFile - sizeof (ZYXHEAD) > ulBytes)
  2377.    {
  2378.       res = DosSetFileSize(hRec, fs.cbFile - ulBytes);
  2379.       if (res)
  2380.       {
  2381.          LogDosMessage(res, 18, NULL);
  2382.          return 2;
  2383.       }
  2384.    }
  2385.  
  2386.    prxsRet->strptr = NULL;
  2387.    return 0;
  2388. }
  2389.  
  2390.  
  2391. static signed _System MyExitHandler
  2392. (
  2393.    LONG lFunc,
  2394.    LONG lSubFunc,
  2395.    PEXIT pchParm
  2396. )
  2397. {
  2398.    static CHAR szVarRings[]="VAMRINGS";
  2399.    static CHAR szVarMsgs[]="VAMMSGS";
  2400.    static CHAR szVarMsgPat[]="VAMMSGPAT";
  2401.    static SHVBLOCK shvb[] = {
  2402.                               {shvb+1, {sizeof szVarRings - 1, szVarRings}},
  2403.                               {shvb+2, {sizeof szVarMsgs - 1, szVarMsgs}},
  2404.                               {NULL, {sizeof szVarMsgPat - 1, szVarMsgPat}}
  2405.                             };
  2406.    APIRET res;
  2407.    CHAR achRings[3], achMsgs[10];
  2408.    ULONG ulLen, ulVal;
  2409.  
  2410.    switch (lFunc)
  2411.    {
  2412.    case RXINI:
  2413.       if (lSubFunc != RXINIEXT)
  2414.          return RXEXIT_NOT_HANDLED;
  2415.       if (fDebug)
  2416.          dprintf("Initializing Rexx function\n");
  2417.  
  2418.       shvb[0].shvcode=RXSHV_SET;
  2419.       shvb[0].shvret=0;
  2420.       _ltoa(ParamBlock.ulRings, achRings, 10);
  2421.       ulLen=strlen(achRings);
  2422.       MAKERXSTRING(shvb[0].shvvalue, achRings, ulLen);
  2423.       shvb[0].shvvaluelen=ulLen;
  2424.  
  2425.       shvb[1].shvcode=RXSHV_SET;
  2426.       shvb[1].shvret=0;
  2427.       _ltoa(ulRecMessages, achMsgs, 10);
  2428.       ulLen=strlen(achMsgs);
  2429.       MAKERXSTRING(shvb[1].shvvalue, achMsgs, ulLen);
  2430.       shvb[1].shvvaluelen=ulLen;
  2431.  
  2432.       shvb[2].shvcode=RXSHV_SET;
  2433.       shvb[2].shvret=0;
  2434.       ulLen=strlen(ParamBlock.szMessagePattern);
  2435.       MAKERXSTRING(shvb[2].shvvalue, ParamBlock.szMessagePattern, ulLen);
  2436.       shvb[2].shvvaluelen=ulLen;
  2437.  
  2438.       res=RexxVariablePool(shvb);
  2439.       if (fDebug)
  2440.          dprintf("RexxVariablePool=%u\n", res);
  2441.       return RXEXIT_HANDLED;
  2442.  
  2443.    case RXTER:
  2444.       if (lSubFunc != RXTEREXT)
  2445.          return RXEXIT_NOT_HANDLED;
  2446.       if (fDebug)
  2447.          dprintf("Cleaning up after Rexx function\n");
  2448.  
  2449.       shvb[0].shvcode=RXSHV_FETCH;
  2450.       shvb[0].shvret=0;
  2451.       MAKERXSTRING(shvb[0].shvvalue, achRings, sizeof achRings - 1);
  2452.       shvb[0].shvvaluelen=sizeof achRings - 1;
  2453.       res=RexxVariablePool(shvb);
  2454.       if (fDebug)
  2455.          dprintf("RexxVariablePool=%u\n", res);
  2456.  
  2457.       achRings[RXSTRLEN(shvb[0].shvvalue)]='\0';
  2458.       ulVal=atol(achRings);
  2459.       if (ulVal != ParamBlock.ulRings)
  2460.       {
  2461.          if (fDebug)
  2462.             dprintf("RINGS have changed %u => %u\n", ParamBlock.ulRings, ulVal);
  2463.          ParamBlock.ulRings=ulVal;
  2464.          IniPutL("Rings", ParamBlock.ulRings); // Rings before answer
  2465.       }
  2466.       return RXEXIT_HANDLED;
  2467.  
  2468.    case RXSIO:
  2469.       if (lSubFunc == RXSIOSAY || lSubFunc == RXSIOTRC)
  2470.       {
  2471.          PrintRxSIO(((RXSIOSAY_PARM *)pchParm)->rxsio_string.strptr);
  2472.          return RXEXIT_HANDLED;
  2473.       }
  2474.       break;
  2475.    }
  2476.    return RXEXIT_NOT_HANDLED;
  2477. }
  2478.  
  2479.  
  2480. static APIRET RegMyREXXFun(void)
  2481. {
  2482.    static struct
  2483.    {
  2484.       PSZ pszName;
  2485.       PFN pfnEntry;
  2486.    } Am4PmCmds[]=
  2487.    {
  2488.       {"AMGetHotComm",          AMGetHotComm},
  2489.       {"AMReleaseHotComm",      AMReleaseHotComm},
  2490.       {"AMDPrint",              AMDPrint},
  2491.       {"AMOpenRecFile",         AMOpenRecFile},
  2492.       {"AMCloseRecFile",        AMCloseRecFile},
  2493.       {"AMPlayFile",            AMPlayFile},
  2494.       {"AMStartRec",            AMStartRec},
  2495.       {"AMEndRec",              AMEndRec},
  2496.       {"AMStartListenDLECode",  AMStartListenDLECode},
  2497.       {"AMEndListenDLECode",    AMEndListenDLECode},
  2498.       {"AMWaitDLECode",         AMWaitDLECode},
  2499.       {"AMSendW",               AMSendW},
  2500.       {"AMGetMoreDCEResp",      AMGetMoreDCEResp},
  2501.       {"AMStartProg",           AMStartProg},
  2502.       {"AMSetStateText",        AMSetStateText},
  2503.       {"AMSetLastEventText",    AMSetLastEventText},
  2504.       {"AMOpenComm",            AMOpenComm},
  2505.       {"AMCloseComm",           AMCloseComm},
  2506.       {"AMReadIni",             AMReadIni},
  2507.       {"AMWriteIni",            AMWriteIni},
  2508.       {"AMInp",                 AMInp},
  2509.       {"AMOutp",                AMOutp},
  2510.       {"AMTrimFileEnd",         AMTrimFileEnd},
  2511.       {"AMSendAT",              AMSendAT},
  2512.       {"AMLog",                 AMLog},
  2513.    };
  2514.  
  2515.    ULONG res;
  2516.    USHORT i;
  2517.  
  2518.  
  2519.    for (i=0; i<sizeof Am4PmCmds / sizeof Am4PmCmds[0]; i++)
  2520.    {
  2521.       res=RexxRegisterFunctionExe(Am4PmCmds[i].pszName, Am4PmCmds[i].pfnEntry);
  2522.       if (res)
  2523.       {
  2524.          LogNumMessage(8, res, Am4PmCmds[i].pszName, NULL);
  2525.          return res;
  2526.       }
  2527.    }
  2528.  
  2529.    res=RexxRegisterExitExe(szExitName, MyExitHandler, NULL);
  2530.    if (res)
  2531.    {
  2532.       LogNumMessage(15, res, NULL);
  2533.       return res;
  2534.    }
  2535.  
  2536.    return 0;
  2537. }
  2538.  
  2539.  
  2540. void WriteModemThread(PVOID lpVar)
  2541. {
  2542.    dprintf("Writing thread started\n");
  2543.  
  2544.    RegMyREXXFun();
  2545.  
  2546.    DosCreateMutexSem(szSemCom, &semCom, 0, 0);
  2547.  
  2548.    DosCreateEventSem(NULL, &semStopRead, 0, TRUE);
  2549.    DosCreateEventSem(NULL, &semStopedReading, 0, FALSE);
  2550.    DosCreateEventSem(NULL, &semGoOnRead, 0, FALSE);
  2551.    DosCreateEventSem(NULL, &semQueueFull, 0, FALSE);
  2552.    DosCreateEventSem(NULL, &semQueueEmpty, 0, FALSE);
  2553.  
  2554.    DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
  2555.  
  2556.    thidRec = _beginthread(ReadModem, NULL, RSTACKSIZE, NULL);
  2557.    DosWaitEventSem(semStopedReading, SEM_INDEFINITE_WAIT);
  2558.    WinPostMsg(hwndFrame, WMU_THREADSUP, 0l, 0l);
  2559.  
  2560.    // Start processing
  2561.    makeit();
  2562.  
  2563.    ShutDown();
  2564.  
  2565.    if (hCom)
  2566.    {
  2567.       SaveRestComMode(FALSE);
  2568.       DosClose(hCom);
  2569.       hCom=0l;
  2570.       DosReleaseMutexSem(semCom);
  2571.    }
  2572.  
  2573.  
  2574.    DosCloseEventSem(semStopRead);
  2575.    DosCloseEventSem(semStopedReading);
  2576.    DosCloseEventSem(semGoOnRead);
  2577.    DosCloseEventSem(semQueueFull);
  2578.    DosCloseEventSem(semQueueEmpty);
  2579.    WinPostMsg(hwndFrame, WMU_THREADSDOWN, 0l, 0l);
  2580. }
  2581.  
  2582.